package com.gingko.duominuo.viewmodel

import androidx.hilt.Assisted
import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import com.gingko.duominuo.data.Resource
import com.gingko.duominuo.data.TaskConfigVo
import com.gingko.duominuo.data.asResource
import com.gingko.duominuo.data.isSuccess
import com.gingko.duominuo.data.model.*
import com.gingko.duominuo.data.request.*
import com.gingko.duominuo.data.source.repository.GinkgoRepository
import com.gingko.duominuo.network.download.OSSUpload
import com.gingko.duominuo.network.exception.ServerException
import com.gingko.duominuo.utils.getTimeSpan
import com.gingko.duominuo.utils.md5
import com.gingko.duominuo.utils.string2Millis
import com.gingkor.common.ext.toJson
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import java.util.concurrent.TimeUnit

class WorkOrderViewModel @ViewModelInject constructor(
    private val ginkgoRepository: GinkgoRepository,
    @Assisted
    val state: SavedStateHandle
) : BaseViewModel() {
    private val _workOrderLiveData = MutableLiveData<Resource<WorkOrderVo>>()
    val workOrderLiveData: LiveData<Resource<WorkOrderVo>> = _workOrderLiveData
    private val _workOrderDetailLiveData = MutableLiveData<Resource<WorkOrderDetailVo>>()
    val workOrderDetailLiveData: LiveData<Resource<WorkOrderDetailVo>> = _workOrderDetailLiveData
    private val _jobReviewContentLiveData = MutableLiveData<Resource<JobReviewContentVo>>()
    val jobReviewContentLiveData: LiveData<Resource<JobReviewContentVo>> = _jobReviewContentLiveData
    private val _countdownLiveData = MutableLiveData<Long>()
    val countdownLiveData: LiveData<Long> = _countdownLiveData
    private var countdownJob: Job? = null
    private val _submitTaskLiveData = MutableLiveData<Resource<String>>()
    val submitTaskLiveData: LiveData<Resource<String>> = _submitTaskLiveData
    private val _jsCommandLiveData = MutableLiveData<List<InjectAndInterceptVo>>()
    private val _urlInterceptLiveData = MutableLiveData<List<InjectAndInterceptVo>>()
    private val _taskConfigLiveData = MutableLiveData<TaskConfigVo?>()
    private var taskMaxTime: Long? = null


    fun getUnFinishWorkOrder(isFirstLoad: Boolean) {
        launchOnUI(
            task = {
                val result = ginkgoRepository.getWorkOrder(OrderReqVo(status = 0))
                val data = result.data?.list_order ?: listOf()
                if (result.isSuccess() && data.isNotEmpty()) {
                    if (_countdownLiveData.value == 0L) {
                        _workOrderLiveData.value = Resource.Success(null)
                    } else {
                        val workOrderVo = data.first()
                        getWorkOrderDetail(OrderDetailReqVo(workOrderVo.id))
                        _workOrderLiveData.value = Resource.Success(workOrderVo)
                    }
                } else {
                    _workOrderLiveData.value = Resource.Success(null)
                }
            },
            onFailure = {
                _workOrderLiveData.value = Resource.Error(it)
            },
        )

    }

    private fun getWorkOrderDetail(orderDetailReqVo: OrderDetailReqVo) {
        launchOnUI(
            task = {
                val result = ginkgoRepository.getWorkOrderDetail(orderDetailReqVo)
                val localData = ginkgoRepository.queryJobWork(orderDetailReqVo.id!!)
                result.data?.data?.firstOrNull()?.data?.let {
                    getJobReviewContent(it.job_id!!)
                }
                localData?.let {
                    result.data?.data?.forEach { workOrderItem ->
                        val localWorkOrderItem =
                            localData.firstOrNull { it.jobId == workOrderItem.id }
                        workOrderItem.reviewStatus = localWorkOrderItem?.status != null
                    }
                }
                _workOrderDetailLiveData.value = result.asResource()
            },
            onFailure = {
                _workOrderDetailLiveData.value = Resource.Error(it)
            }, isShowLoading = false
        )

    }

    private fun getJobReviewContent(jobId: String) {
        launchOnUI(
            task = {
                _jobReviewContentLiveData.value =
                    ginkgoRepository.getJobReviewContent(jobId).asResource()
            },
            onFailure = {
                _jobReviewContentLiveData.value = Resource.Error(it)
            }, isShowLoading = false
        )
    }

    fun loadReviewTaskFromDB(workId: String) {
        launchOnUI(
            task = {
                val workOrderDetail = workOrderDetailLiveData.value
                val localData = ginkgoRepository.queryJobWork(workId)
                localData?.let {
                    workOrderDetail?.data?.data?.forEach { workOrderItem ->
                        val localWorkOrderItem =
                            localData.firstOrNull { it.jobId == workOrderItem.id }
                        workOrderItem.reviewStatus = localWorkOrderItem?.status != null
                    }
                }
                _workOrderDetailLiveData.value = workOrderDetail
            }, isShowLoading = false
        )
    }

    fun startTaskCountdown(createTime: String) {
        if (countdownJob?.isActive == true) {
            countdownJob?.cancel()
        }
        if (taskMaxTime == null) {
            launchOnUI(
                task = {
                    val configResult = ginkgoRepository.getTaskConfig()
                    taskMaxTime = configResult.order_expiration_time
                    startCountdown(createTime)
                }, isShowLoading = false
            )
        } else {
            startCountdown(createTime)
        }
    }

    private fun startCountdown(createTime: String) {
        val maxTime = taskMaxTime ?: 3 * 60 * 60
        val outTimeMills = string2Millis(createTime, "yyyy-MM-dd HH:mm:ss") + maxTime * 1000
        val timeSpan = System.currentTimeMillis().getTimeSpan(outTimeMills, TimeUnit.SECONDS)
        if (System.currentTimeMillis() >= outTimeMills) {
            _countdownLiveData.value = 0
        } else {
            countdownJob = launchOnUI(
                task = {
                    flow {
                        for (time in timeSpan downTo 0) {
                            emit(time)
                            delay(1000)
                        }
                    }.collect {
                        _countdownLiveData.value = it
                    }
                }, isShowLoading = false
            )
        }
    }


    fun submitTask(taskId: String) {
        launchOnUI(
            task = {
                val submitWorkOrderReqVo = SubmitWorkOrderReqVo(id = taskId, data = mutableListOf())
                ginkgoRepository.queryJobWork(taskId)?.forEach {
                    val reviewInfoVo = ReviewInfoVo(id = it.jobId)
                    reviewInfoVo.count.digg_count = it.digg_count ?: -1
                    reviewInfoVo.count.share_count = it.share_count ?: -1
                    reviewInfoVo.count.comment_count = it.comment_count ?: -1
                    reviewInfoVo.count.click_count = it.click_count ?: -1
                    reviewInfoVo.count.collect_count = it.collect_count ?: -1
                    reviewInfoVo.status = it.status
                    reviewInfoVo.extra.images = it.images
                    reviewInfoVo.extra.perfect = it.perfect
                    reviewInfoVo.extra.reject_reason = it.reject_reason
                    submitWorkOrderReqVo.data.add(reviewInfoVo)
                }
                submitWorkOrderReqVo.signature = submitWorkOrderReqVo.data.toJson().md5()
                _submitTaskLiveData.value =
                    ginkgoRepository.submitWorkOrder(submitWorkOrderReqVo).asResource()
            }, onFailure = {
                _submitTaskLiveData.value = Resource.Error(it)
            }
        )

    }

    fun getInterceptAndInject() {
        launchOnUI(
            task = {
                launch {
                    val injectUrl = OSSUpload.RESOURCE_DATA_END_POINT + "/inject.json"
                    val injectResult = ginkgoRepository.getInterceptAndInject(injectUrl)
                    _jsCommandLiveData.value = injectResult
                }
                launch {
                    val interceptUrl = OSSUpload.RESOURCE_DATA_END_POINT + "/block.json"
                    val interceptResult = ginkgoRepository.getInterceptAndInject(interceptUrl)
                    _urlInterceptLiveData.value = interceptResult
                }
            }, isShowLoading = false
        )
    }


    fun getInjectAndInterceptByPlatform(app: String?): InjectAndInterceptVo {
        val injectVo = _jsCommandLiveData.value?.firstOrNull() { it.platform == app }
        val interceptVo = _urlInterceptLiveData.value?.firstOrNull() { it.platform == app }
        return InjectAndInterceptVo(app, injectVo?.js, interceptVo?.pattern)
    }

}